package com.ivanceras.server.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
import com.google.appengine.tools.remoteapi.RemoteApiOptions;
import com.ivanceras.shared.meta.ModelDefinitionProvider;
import com.ivanceras.shared.db.DAO;
import com.ivanceras.shared.db.EMF;
import com.ivanceras.shared.db.EntityManager;
import com.ivanceras.shared.db.IModelDef;
import com.ivanceras.shared.exception.DatabaseException;
import com.ivanceras.shared.exception.ModelDefinitionNotFoundException;

public class DataImporter {

	private static DAO[] parseXmlFile() throws DatabaseException{
		List<DAO> daoList = new ArrayList<DAO>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();

			Document dom = db.parse(Configuration.generatedDataDirectory+Configuration.generatedDataFile);
			Element root = dom.getDocumentElement();
			System.out.println("root: "+root.getNodeName());
			NodeList models = dom.getElementsByTagName("model");
			System.out.println("inside root: "+models.getLength());
			int totalModel = models.getLength();
			
			for(int i = 0; i < totalModel; i++){
				Node nmodel = models.item(i);
				if(nmodel.getNodeType() == Node.ELEMENT_NODE){
					String table = ((Element)nmodel).getAttribute("name");
					String prettyTableName = ((Element)nmodel).getAttribute("pretty");
					NodeList rowList = ((Element)nmodel).getElementsByTagName("row");
					int totalRows = rowList.getLength();
					String daoModelName = CStringUtils.capitalize(table);
					IModelDef modeldef = null;
					try {
						modeldef = ModelDefinitionProvider.getDefinition(daoModelName);
					} 
					catch (ModelDefinitionNotFoundException e) {
						e.printStackTrace();
						throw new DatabaseException("No Model definition found");
					}
					String[] model_attributes = modeldef.getAttributes();
					String[] model_datatypes = modeldef.getDataTypes();
					
					for(int r = 0; r < totalRows; r++){
						Node row = rowList.item(r);
						if(row.getNodeType() == Node.ELEMENT_NODE){
							NodeList attributes = ((Element)row).getChildNodes();
							DAO dao = new DAO(CStringUtils.capitalize(table));
							int totalAttributes = attributes.getLength();
							for(int a = 0; a < totalAttributes; a++){
								Node attrib = attributes.item(a);
								if(attrib.getNodeType() == Node.ELEMENT_NODE){
									Node nvalue = attrib.getFirstChild();
									if(nvalue.getNodeType() == Node.CDATA_SECTION_NODE){
										String attribute = attrib.getNodeName();
										String s_value = nvalue.getNodeValue();
//										System.out.println(" "+attribute+" = "+s_value);
										String dataType = model_datatypes[indexOf(model_attributes, attribute)]; 
										Object o_value = DataTypeUtils.convertFromString(s_value, dataType);
										dao.set_Value(attribute, o_value);
									}
								}
							}
							daoList.add(dao);
						}
					}
				}
			}

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
		return daoList.toArray(new DAO[daoList.size()]);
	}
	
	private static int indexOf(String[] attributes, String key){
		for(int i = 0; i < attributes.length; i++){
			if(key.equals(attributes[i])){
				return i;
			}
		}
		return -1;
	}

	public static void importDAO(DAO[] daoList, String startTable) throws DatabaseException{
		EntityManager em = null;
		try {
			em = EMF.get();
			//em.beginTransaction();
			importDAO(em, daoList, startTable);
			//em.commitTransaction();
		}
		catch(DatabaseException e){
			em.rollbackTransaction();
			e.printStackTrace();
			throw new DatabaseException();
		}
		finally{
			em.close();
		}
	}
	
	private static void importDAO(EntityManager em, DAO[] daoList, String startTable) throws DatabaseException{
		System.out.println("Importing dao: "+daoList.length);
		boolean started = false;
		if(startTable == null){
			started = true; //start right away
		}
		for(int i = 0; i < daoList.length; i++){
			DAO dao = daoList[i];
			if(startTable != null && dao.getModelName().equals(startTable)){
				System.out.println("STARTING NOW.........");
				started = true;
			}
			if(started){
				System.out.println("Importing "+dao.getModelName()+" now....");
				System.out.println(" \t["+dao.getProperties()+"]");
				em.insert(dao);
			}
			else{
				System.err.println("NOT YET: "+dao.getModelName());
			}
		}
	}
	
	public static void main(String[] args) throws DatabaseException, IOException{
		System.out.println("Starting a remove import to the demo server");
        String username = "uremail@gmail.com";
        String password = "urpasswd";
        RemoteApiOptions options = new RemoteApiOptions()
            .server("localhost", 8080)
            .credentials(username, password);
//        RemoteApiInstaller installer = new RemoteApiInstaller();
//        installer.install(options);
		DAO[] daoList = parseXmlFile();
		importDAO(daoList, null);
	}
}
